﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.ServiceModel;
using System.Threading;
using System.Threading.Tasks;
using landlord2lib;
using landlord2server.Properties;

namespace landlord2server
{
    public class GameHost
    {
        private static GameHost g_host = new GameHost();

        private ServiceHost m_host;

        private Dictionary<Guid, GameClient> m_clients = new Dictionary<Guid, GameClient>();
        private Dictionary<Guid, GamePlayer> m_players = new Dictionary<Guid, GamePlayer>();
        private GameTable[] m_tables;

        public GameHost()
        {
            InitService();

            m_tables = new GameTable[Settings.Default.MaxTableCount];
            for (int i = 0; i < m_tables.Length; i++) m_tables[i] = new GameTable(i);
        }

        private void InitService()
        {
            string uri = string.Format("net.tcp://0.0.0.0:{0}/landlord2", Settings.Default.HostPort);

            m_host = new ServiceHost(typeof(GameClient));
            NetTcpBinding binding = new NetTcpBinding();
            binding.Security.Mode = SecurityMode.None;
            binding.ReliableSession.Enabled = true;
            binding.ReliableSession.Ordered = true;
            binding.ReliableSession.InactivityTimeout = TimeSpan.FromSeconds(15);
            m_host.AddServiceEndpoint(typeof(IClient), binding, uri);
            m_host.Open();
            m_host.Closed += ServiceHost_Closed;
            m_host.Faulted += ServiceHost_Faulted;
        }

        private void ServiceHost_Faulted(object sender, EventArgs e)
        {
        }

        private void ServiceHost_Closed(object sender, EventArgs e)
        {
        }

        public static GameHost Current
        {
            get
            {
                return g_host;
            }
        }

        public void Regist(GameClient client, string name, int gender)
        {
            m_clients.Add(client.Guid, client);
            GamePlayer player = new GamePlayer(client.Guid, name, gender);
            m_players.Add(player.Guid, player);
        }

        public void Unregist(GameClient client)
        {
            if (client.CurrentWindow == 0) ClearSeat(client);
            else if (client.CurrentWindow == 1)
            {
                GamePlayer player = m_players[client.Guid];
                if (player.Table != null)
                {
                    if (m_tables[player.Table.Value].Status == 1)
                    {
                        GamePlayer[] players = m_tables[player.Table.Value].GetPlayers();
                        m_tables[player.Table.Value] = new GameTable(player.Table.Value);
                        foreach (GamePlayer player2 in players)
                        {
                            GameClient client2 = m_clients[player2.Guid];
                            if (client == client2) continue;
                            try
                            {
                                client2.GetCallback().OtherDisconnect();
                            }
                            catch { }
                        }
                    }
                }
            }
            m_clients.Remove(client.Guid);
            m_players.Remove(client.Guid);
        }

        public DataSet GetTableList()
        {
            DataSet ds = GameTable.CreateDataSet();
            foreach (GameTable table in m_tables)
            {
                DataRow row = ds.Tables[0].NewRow();
                row["Index"] = table.Index;
                row["PlayerCount"] = table.PlayerCount;
                row["Status"] = table.Status;
                string[] players = table.Players;
                for (int i = 0; i < 4; i++) row["Player" + (i + 1).ToString()] = players[i];
                ds.Tables[0].Rows.Add(row);
            }
            return ds;
        }

        public void Callback_TableList(GameClient except)
        {
            DataSet ds = GetTableList();
            foreach (GameClient client in m_clients.Values)
            {
                if (client == except) continue;
                if (client.CurrentWindow != 0) continue;
                try
                {
                    client.GetCallback().TableList(ds);
                }
                catch { }
            }
        }

        public DataSet SetSeat(GameClient client, int table, int seat)
        {
            GamePlayer player = m_players[client.Guid];
            if (m_tables[table].Status != 0) return null;
            if (m_tables[table].SetSeat(seat, player))
            {
                for (int i = 0; i < m_tables.Length; i++)
                {
                    if (i == table) continue;
                    m_tables[i].ClearSeat(player);
                }
                player.Table = table;
                player.Seat = seat;

                Callback_TableList(client);
                if (m_tables[table].CanStart)
                {
                    m_tables[table].Status = 1;
                    GamePlayer[] players = m_tables[table].GetPlayers();
                    foreach (GamePlayer player2 in players)
                    {
                        GameClient client2 = m_clients[player2.Guid];
                        try
                        {
                            if (client2 == client) client2.GetCallback().OpenMainWindow();
                            else client2.GetCallback().OpenMainWindow();
                        }
                        catch { }
                    }
                }
                return GetTableList();
            }
            else return null;
        }

        public DataSet ClearSeat(GameClient client)
        {
            GamePlayer player = m_players[client.Guid];
            foreach (GameTable table in m_tables)
            {
                if (table.ClearSeat(player))
                {
                    player.Table = null;
                    player.Seat = null;
                    Callback_TableList(client);
                    return GetTableList();
                }
            }
            return null;
        }

        public DataSet GetPlayerInfo(GameClient client)
        {
            int? t = m_players[client.Guid].Table;
            if (t == null) return null;
            DataSet ds = GamePlayer.CreateDataSet();
            GameTable table = m_tables[t.Value];
            foreach (GamePlayer player in table.GetPlayers())
            {
                DataRow row = ds.Tables[0].NewRow();
                row["Name"] = player.Name;
                row["Gender"] = player.Gender;
                row["Point"] = player.Point;
                ds.Tables[0].Rows.Add(row);
            }
            return ds;
        }

        public void SetReady(GameClient client)
        {
            int? t = m_players[client.Guid].Table;
            if (t == null) return;
            GameTable table = m_tables[t.Value];
            GamePlayer player = m_players[client.Guid];
            player.Ready = true;
            bool allReady = true;
            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().PlayerReady(player.Seat.Value);
                }
                catch { }
                if (!player2.Ready) allReady = false;
            }
            SendChatText(table, string.Format("{0}已准备", player.Name));
            if (allReady) GenerateCards(table);
        }

        private void GenerateCards(GameTable table)
        {
            CardKind[] kinds = (CardKind[])Enum.GetValues(typeof(CardKind));
            CardPoint[] points = (CardPoint[])Enum.GetValues(typeof(CardPoint));

            List<Card> allCards = new List<Card>();
            foreach (CardKind kind in kinds)
            {
                foreach (CardPoint point in points)
                {
                    if (point == CardPoint.CardJoker || point == CardPoint.CardGJoker) continue;
                    allCards.Add(new Card(kind, point));  
                    allCards.Add(new Card(kind, point));
                }
            }
            allCards.Add(new Card(null, CardPoint.CardJoker));
            allCards.Add(new Card(null, CardPoint.CardJoker));
            allCards.Add(new Card(null, CardPoint.CardGJoker));
            allCards.Add(new Card(null, CardPoint.CardGJoker));

            Random rand = new Random();
            List<Card>[] playersCards = new List<Card>[4];
            List<Card> lordCards = new List<Card>();
            for (int n = 0; n < 25; n++)
            {
                for (int i = 0; i <= playersCards.Length; i++)
                {
                    if (i == playersCards.Length)
                    {
                        if (lordCards.Count < 8)
                        {
                            int index = rand.Next(allCards.Count);
                            lordCards.Add(allCards[index]);
                            allCards.RemoveAt(index);
                        }
                    }
                    else
                    {
                        if (playersCards[i] == null) playersCards[i] = new List<Card>();
                        List<Card> playerCards = playersCards[i];
                        int index = rand.Next(allCards.Count);
                        playerCards.Add(allCards[index]);
                        allCards.RemoveAt(index);
                    }
                }
            }

            table.LordCards = lordCards.ToArray();
            table.PlayersCards = playersCards;

            table.CurrentDir = rand.Next(4);
            int dir = table.CurrentDir.Value;
            GamePlayer[] players = table.GetPlayers();
            for (int i = 0; i < players.Length; i++)
            {
                GamePlayer player = players[(dir + i) % players.Length];
                GameClient client = m_clients[player.Guid];
                try
                {
                    client.GetCallback().GenerateCard(playersCards[i].ToArray());
                    client.GetCallback().CallLord(dir, 0);
                }
                catch { }
            }
            SendChatText(table, string.Format("轮到{0}叫地主", players[dir].Name));
        }

        public void CallLord(GameClient client, int call)
        {
            GamePlayer player = m_players[client.Guid];
            if (player.Table == null || player.Seat == null) return;
            GameTable table = m_tables[player.Table.Value];

            if (table.CallLord == null) table.CallLord = new int[4];
            table.CallLord[player.Seat.Value] = call;

            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().CallLordResult(player.Seat.Value, call);
                }
                catch { }
            }
            if (call == 0) SendChatText(table, string.Format("{0}不叫地主", player.Name));
            else SendChatText(table, string.Format("{0}叫地主，底分{1}分", player.Name, call));

            if (call == 3 || (player.Seat.Value + 1) % 4 == table.CurrentDir.Value)
            {
                int? callSeat = null;
                int point = 0;

                for (int i = 3; i > 0; i--)
                {
                    for (int j = 0; j < 4; j++)
                    {
                        int dir = (table.CurrentDir.Value + j) % 4;
                        if (table.CallLord[dir] == i)
                        {
                            callSeat = dir;
                            point = i;
                            break;
                        }
                    }
                    if (callSeat != null) break;
                }

                if (callSeat == null)
                {
                    callSeat = table.CurrentDir.Value;
                    point = 1;
                }

                table.LordDir = callSeat;
                table.Point = point;
                table.CurrentDir = callSeat;
                GamePlayer player2 = table.GetPlayers()[callSeat.Value];
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().GiveLordCard(table.LordCards, point);
                }
                catch { }
                SendChatText(table, string.Format("当前地主为{0}，底分为{1}分", player2.Name, point));

                foreach (GamePlayer player3 in table.GetPlayers())
                {
                    GameClient client3 = m_clients[player3.Guid];
                    if (client3 == client2) continue;
                    try
                    {
                        client3.GetCallback().ShowLordCard(player2.Seat.Value, table.LordCards, point);
                    }
                    catch { }
                }
                Callback_SendCard(table);
            }
            else
            {
                int dir = (player.Seat.Value + 1) % 4;
                GamePlayer player2 = table.GetPlayers()[dir];
                GameClient client2 = m_clients[player2.Guid];
                foreach (GamePlayer player3 in table.GetPlayers())
                {
                    GameClient client3 = m_clients[player3.Guid];
                    try
                    {
                        client3.GetCallback().CallLord(dir, call);
                    }
                    catch { }
                }
                SendChatText(table, string.Format("轮到{0}叫地主", player2.Name));
            }
        }

        private void Callback_SendCard(GameTable table)
        {
            foreach (GamePlayer player in table.GetPlayers())
            {
                GameClient client = m_clients[player.Guid];
                try
                {
                    client.GetCallback().SendCard(table.CurrentDir.Value);
                }
                catch { }
            }
        }

        public bool SendCard(GameClient client, Card[] cards, bool end)
        {
            GamePlayer player = m_players[client.Guid];
            if (player.Table == null || player.Seat == null) return false;
            GameTable table = m_tables[player.Table.Value];

            bool bigger = false;

            if (cards != null)
            {
                CardGroup group = CardGroup.AssignCardGroup(cards);
                if (group == null) return false;
                if (table.LastCardGroup != null && group.CompareTo(table.LastCardGroup) <= 0) return false;
                bigger = table.LastCardGroup != null;
                table.LastCardGroup = group;
                table.LastDir = player.Seat.Value;
            }
            else
            {
                if (table.LastCardGroup == null) return false;
            }

            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().SendCardResult(player.Seat.Value, cards, bigger);
                }
                catch { }
            }
            if (!end)
            {
                table.CurrentDir = (player.Seat.Value + 1) % 4;
                if (table.CurrentDir.Value == table.LastDir.Value)
                {
                    table.LastCardGroup = null;
                    table.LastDir = null;
                }
                Callback_SendCard(table);
            }
            else
            {
                new Task(() =>
                {
                    Thread.Sleep(500);
                    GamePlayer[] players = table.GetPlayers();
                    bool[] win = new bool[4];
                    int[] delta = new int[4];
                    if (player.Seat.Value == table.LordDir.Value)
                    {
                        for (int i = 0; i < delta.Length; i++)
                        {
                            if (i == table.LordDir.Value)
                            {
                                delta[i] += table.Point.Value * 3;
                                win[i] = true;
                            }
                            else
                            {
                                delta[i] -= table.Point.Value;
                                win[i] = false;
                            }
                            players[i].Point += delta[i];
                        }
                        SendChatText(table, "游戏结束，地主赢");
                    }
                    else
                    {
                        for (int i = 0; i < delta.Length; i++)
                        {
                            if (i == table.LordDir.Value)
                            {
                                delta[i] -= table.Point.Value * 3;
                                win[i] = false;
                            }
                            else
                            {
                                delta[i] += table.Point.Value;
                                win[i] = true;
                            }
                            players[i].Point += delta[i];
                        }
                        SendChatText(table, "游戏结束，地主输");
                    }
                    DataSet ds = new DataSet();
                    DataTable dt = ds.Tables.Add("GameResult");
                    dt.Columns.Add("Name", typeof(string));
                    dt.Columns.Add("Delta", typeof(int));
                    dt.Columns.Add("Point", typeof(int));
                    SendChatText(table, "本局游戏结果：");
                    for (int i = 0; i < players.Length; i++)
                    {
                        DataRow row = dt.NewRow();
                        row["Name"] = players[i].Name;
                        row["Delta"] = delta[i];
                        row["Point"] = players[i].Point;
                        dt.Rows.Add(row);
                        SendChatText(table, string.Format("{0}得{1}分，共{2}分", players[i].Name, delta[i], players[i].Point));
                    }
                    for (int i = 0; i < players.Length; i++)
                    {
                        GameClient client2 = m_clients[players[i].Guid];
                        try
                        {
                            client2.GetCallback().GameResult(ds, win[i]);
                        }
                        catch { }
                    }
                    SendChatText(table, "开始新牌局");
                    RestartGame(table, player.Seat.Value);
                }).Start();
            }
            return true;
        }

        private void RestartGame(GameTable table, int currentDir)
        {
            foreach (GamePlayer player in table.GetPlayers()) player.Ready = false;
            table.LordCards = null;
            table.CurrentDir = currentDir;
            table.PlayersCards = null;
            table.CallLord = null;
            table.LastCardGroup = null;
            table.LastDir = null;
            table.LordDir = null;
            table.Point = null;
            foreach (GamePlayer player in table.GetPlayers())
            {
                GameClient client = m_clients[player.Guid];
                try
                {
                    client.GetCallback().RestartGame();
                }
                catch { }
            }
        }

        public void SendChat(GameClient client, int gender, int index)
        {
            GamePlayer player = m_players[client.Guid];
            if (player.Table == null || player.Seat == null) return;
            GameTable table = m_tables[player.Table.Value];
            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().SendChat(player.Seat.Value, gender, index);
                }
                catch { }
            }
            string text = "";
            switch (index)
            {
                case 0: text = "不要吵了不要吵了,专心玩游戏吧"; break;
                case 1: text = "不要走,决战到天亮"; break;
                case 2: text = "大家好,很高兴见到各位"; break;
                case 3: text = "各位真是不好意思,我要离开一会儿"; break;
                case 4: text = "和你合作真是太愉快了"; break;
                case 5: text = "快点啊,等到花儿都谢了"; break;
                case 6: text = "你的牌打的也太好了"; break;
                case 7: text = "你是MM还是GG"; break;
                case 8: text = "交个朋友吧,能告诉我你的联系方法吗"; break;
                case 9: text = "下次再玩吧,我要走了"; break;
                case 10: text = "再见了,我会想念大家的"; break;
                case 11: text = "怎么又断线,网络怎么这么差啊"; break;
            }
            SendChatText(client, text);
        }

        private void SendChatText(GameTable table, string text)
        {
            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().SendChatText(null, text);
                }
                catch { }
            }
        }

        public void SendChatText(GameClient client, string text)
        {
            GamePlayer player = m_players[client.Guid];
            if (player.Table == null || player.Seat == null) return;
            GameTable table = m_tables[player.Table.Value];
            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().SendChatText(player.Seat.Value, text);
                }
                catch { }
            }
        }

        public void RobotPlay(GameClient client, bool ena)
        {
            GamePlayer player = m_players[client.Guid];
            if (player.Table == null || player.Seat == null) return;
            GameTable table = m_tables[player.Table.Value];
            foreach (GamePlayer player2 in table.GetPlayers())
            {
                GameClient client2 = m_clients[player2.Guid];
                try
                {
                    client2.GetCallback().RobotPlay(player.Seat.Value, ena);
                }
                catch { }
            }
        }
    }
}
